<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>使用redis和zookeeper实现分布式锁 - CMS SYSTEM</title>
    <meta name="keywords" content="redis,zookeeper" />
    <meta name="description" content="分布式锁一般用在分布式系统或者多个应用中，用来控制同一任务是否执行或者任务的执行顺序。在项目中，部署了多个tomcat应用，在执行定时任务时就会遇到同一任务可能执行多次的情况，我们可以借助分布式锁，保证在同一时间只有一个tomcat应用执行了定时任务。" />
    <link href="http://localhost:8080/static/www/blog/css/base.css" rel="stylesheet">
    <link href="http://localhost:8080/static/www/blog/css/style.css" rel="stylesheet">
    <link href="http://localhost:8080/static/www/blog/css/media.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
    <!--[if lt IE 9]>
    <script src="http://localhost:8080/static/www/blog/js/modernizr.js"></script>
    <![endif]-->
</head>
<body>
<div class="ibody">
    <header>
        <h1>CMS SYSTEM</h1>
        <h2>Nothing is impossible1....</h2>
        <div class="logo"><a href="http://localhost:8080"></a></div>
        <nav id="topnav">
            <a href="http://localhost:8080/html/1/">首页</a>
                <a href="http://localhost:8080/html/1/45.html">自然堂</a>
                <a href="http://localhost:8080/html/1/180.html">美素</a>
                <a href="http://localhost:8080/html/1/184.html">植物智慧</a>
                <a href="http://localhost:8080/html/1/186.html">关于我们</a>
        </nav>
    </header>
    <article>
            <h2 class="about_h">您现在的位置是:<a href="http://localhost:8080/html/1/">首页</a>>
                <a href="http://localhost:8080/html/1/45.html">自然堂</a>
                >
                <a href="http://localhost:8080/html/1/183.html">程序员</a>
            </h2>
        <div class="index_about">
            <h2 class="c_titile">使用redis和zookeeper实现分布式锁</h2>
            <p class="box_c"><span class="d_time">发布时间：2017-07-23 16:29</span><span>编辑：admin</span><span>浏览（39）</span></p>
            <ul class="infos">
                <p>
                    <h2>1.分布式锁</h2><p>分布式锁一般用在分布式系统或者多个应用中，用来控制同一任务是否执行或者任务的执行顺序。在项目中，部署了多个tomcat应用，在执行定时任务时就会遇到同一任务可能执行多次的情况，我们可以借助分布式锁，保证在同一时间只有一个tomcat应用执行了定时任务。</p><h2>2.分布式锁的实现方式</h2><ol><li>使用redis的setnx()和expire()</li><li>使用redis的getset()</li><li>使用zookeeper的创建节点node</li><li>使用zookeeper的创建临时序列节点</li></ol><h2>3.使用redis的setnx()和expire()来实现分布式锁</h2><pre><code>setnx(key,<span><span><span><span>value</span></span></span></span>) 如果key不存在，设置为当前key的值为<span><span><span><span>value</span></span></span></span>;如果key存在，直接返回。
expire()来设置超时时间
</code></pre><p>定义注解类：</p><pre><code><span><span><span><span>@Target</span></span></span></span>({ElementType.METHOD})
<span><span><span><span>@Retention</span></span></span></span>(RetentionPolicy.RUNTIME)
public <span><span><span><span>@interface</span></span></span></span> Lockable{
    <span><span><span><span>// redis缓存key</span></span></span></span>
    String key();
    <span><span><span><span>// redis缓存key中的数据</span></span></span></span>
    String value() default "";
    <span><span><span><span>// 过期时间(秒)，默认为一分钟</span></span></span></span>
    long expire() default 60;
}
</code></pre><p>定时任务增加注解@Lockable：</p><pre><code> <span><span><span><span>@Lockable</span></span></span></span>(key = <span><span><span><span>"DistributedLock:dealExpireRecords"</span></span></span></span>)
 <span><span><span><span><span><span><span><span>public</span></span></span></span></span></span></span><span><span><span> </span></span></span><span><span><span><span><span><span><span>void</span></span></span></span></span></span></span><span><span><span> </span></span></span><span><span><span><span><span><span><span>dealExpireRecords</span></span></span></span></span></span></span><span><span><span><span><span><span><span>()</span></span></span></span></span></span></span><span><span><span> </span></span></span></span>{
 }
</code></pre><p>定义一个aop切面LockAspect，使用@Around处理所有注解为@Lockable的方法，通过连接点确认此注解是用在方法上，通过方法获取注解信息，使用setIfAbsent来判断是否获取分布式锁，如果没有获取分布式锁，直接返回；如果获取到分布式锁，通过expire设置过期时间，并调用指定方法。</p><pre><code><span><span><span><span>@Component</span></span></span></span>
<span><span><span><span>@Slf4j</span></span></span></span>
<span><span><span><span>@Aspect</span></span></span></span>
<span><span><span><span>public</span></span></span></span> <span><span><span><span><span><span><span><span>class</span></span></span></span></span></span></span><span><span><span> </span></span></span><span><span><span><span><span><span><span>LockAspect</span></span></span></span></span></span></span><span><span><span> </span></span></span></span>{

    <span><span><span><span>@Autowired</span></span></span></span>
    <span><span><span><span>private</span></span></span></span> RedisTemplate redisTemplate;

    <span><span><span><span>@Around(</span></span></span><span><span><span><span><span><span><span>"@annotation(com.records.aop.Lockable)"</span></span></span></span></span></span></span><span><span><span>)</span></span></span></span>
    <span><span><span><span>public</span></span></span></span> Object distributeLock(ProceedingJoinPoint pjp) {
        Object resultObject = <span><span><span><span>null</span></span></span></span>;

        <span><span><span><span>//确认此注解是用在方法上</span></span></span></span>
        Signature signature = pjp.getSignature();
        <span><span><span><span>if</span></span></span></span> (!(signature instanceof MethodSignature)) {
            log.error(<span><span><span><span>"Lockable is method annotation!"</span></span></span></span>);
            <span><span><span><span>return</span></span></span></span> resultObject;
        }

        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();

        <span><span><span><span>//获取注解信息</span></span></span></span>
        Lockable lockable = targetMethod.getAnnotation(Lockable.<span><span><span><span>class</span></span></span></span>);
        String key = lockable.key();
        String value = lockable.value();
        long expire = lockable.expire();

        <span><span><span><span>// 分布式锁，如果没有此key，设置此值并返回true；如果有此key，则返回false</span></span></span></span>
        boolean result = redisTemplate.boundValueOps(key).setIfAbsent(value);
        <span><span><span><span>if</span></span></span></span> (!result) {
            <span><span><span><span>//其他程序已经获取分布式锁</span></span></span></span>
            <span><span><span><span>return</span></span></span></span> resultObject;
        }

        <span><span><span><span>//设置过期时间，默认一分钟</span></span></span></span>
        redisTemplate.boundValueOps(key).expire(expire, TimeUnit.SECONDS);

        <span><span><span><span>try</span></span></span></span> {
            resultObject = pjp.proceed(); <span><span><span><span>//调用对应方法执行</span></span></span></span>
        } <span><span><span><span>catch</span></span></span></span> (Throwable throwable) {
            throwable.printStackTrace();
        }
        <span><span><span><span>return</span></span></span></span> resultObject;
    }
}
</code></pre><h2>4.使用redis的getset()来实现分布式锁</h2><p>此方法使redisTemplate.boundValueOps(key).getAndSet(value)的方法，如果返回空，表示获取了分布式锁；如果返回不为空，表示分布式锁已经被其他程序占用</p><h2>5.使用zookeeper的创建节点node</h2><p>使用zookeeper创建节点node，如果创建节点成功，表示获取了此分布式锁；如果创建节点失败，表示此分布式锁已经被其他程序占用(多个程序同时创建一个节点node，只有一个能够创建成功)</p><h2>6.使用zookeeper的创建临时序列节点</h2><p>使用zookeeper创建临时序列节点来实现分布式锁，适用于顺序执行的程序，大体思路就是创建临时序列节点，找出最小的序列节点，获取分布式锁，程序执行完成之后此序列节点消失，通过watch来监控节点的变化，从剩下的节点的找到最小的序列节点，获取分布式锁，执行相应处理，依次类推......</p><p>本文主要介绍了使用redis和zookeeper实现分布式锁的处理，也可以关注我的公众号：不知风在何处，相互沟通，共同进步。</p><p><br></p>
                </p>
            </ul>
            <div class="keybq">
                <p><span>关键字词</span>：redis,zookeeper</p>
            </div>
            <div class="nextinfo">
                    <p>上一篇：没有了</p>
                    <p>下一篇：没有了</p>

            </div>

        </div>

    </article>
    <aside>
        <div class="rnav">
                <li class="rnav1">
                    <a href="http://localhost:8080/html/1/181.html">产品介绍</a>
                </li>
                <li class="rnav2">
                    <a href="http://localhost:8080/html/1/182.html">知识库</a>
                </li>
                <li class="active rnav3" >
                    <a href="http://localhost:8080/html/1/183.html">程序员</a>
                </li>
        </div>
        <div class="ph_news">
            <h2>
                <p>点击排行</p>
            </h2>
            <ul class="ph_n">
                    <li><span class="num1">1</span>
                        <a href="http://localhost:8080/html/1/183/182.html">使用redis和zookeep...</a></li>
            </ul>
            <h2>
                <p>栏目推荐</p>
            </h2>
            <ul>
                <li><a href="/">有一种思念，是淡淡的幸福,一个心情一行文字</a></li>
            </ul>
            <!--<h2>-->
                <!--<p>最新评论</p>-->
            <!--</h2>-->
            <!--<ul class="pl_n">-->
                <!--<dl>-->
                    <!--<dt><img src="images/s8.jpg"> </dt>-->
                    <!--<dt> </dt>-->
                    <!--<dd>DanceSmile-->
                        <!--<time>49分钟前</time>-->
                    <!--</dd>-->
                    <!--<dd><a href="/">文章非常详细，我很喜欢.前端的工程师很少，我记得几年前yahoo花高薪招聘前端也招不到</a></dd>-->
                <!--</dl>-->
                <!--<dl>-->
                    <!--<dt><img src="images/s7.jpg"> </dt>-->
                    <!--<dt> </dt>-->
                    <!--<dd>yisa-->
                        <!--<time>2小时前</time>-->
                    <!--</dd>-->
                    <!--<dd><a href="/">我手机里面也有这样一个号码存在</a></dd>-->
                <!--</dl>-->
                <!--<dl>-->
                    <!--<dt><img src="images/s6.jpg"> </dt>-->
                    <!--<dt> </dt>-->
                    <!--<dd>小林博客-->
                        <!--<time>8月7日</time>-->
                    <!--</dd>-->
                    <!--<dd><a href="/">博客色彩丰富，很是好看</a></dd>-->
                <!--</dl>-->
                <!--<dl>-->
                    <!--<dt><img src="images/003.jpg"> </dt>-->
                    <!--<dt> </dt>-->
                    <!--<dd>DanceSmile-->
                        <!--<time>49分钟前</time>-->
                    <!--</dd>-->
                    <!--<dd><a href="/">文章非常详细，我很喜欢.前端的工程师很少，我记得几年前yahoo花高薪招聘前端也招不到</a></dd>-->
                <!--</dl>-->
                <!--<dl>-->
                    <!--<dt><img src="images/002.jpg"> </dt>-->
                    <!--<dt> </dt>-->
                    <!--<dd>yisa-->
                        <!--<time>2小时前</time>-->
                    <!--</dd>-->
                    <!--<dd><a href="/">我手机里面也有这样一个号码存在</a></dd>-->
                <!--</dl>-->
            <!--</ul>-->
            <!--<h2>-->
                <!--<p>最近访客</p>-->
                <!--<ul>-->
                    <!--<img src="images/vis.jpg">&lt;!&ndash; 直接使用“多说”插件的调用代码 &ndash;&gt;-->
                <!--</ul>-->
            <!--</h2>-->
        </div>
        <div class="copyright">
            <ul>
                <p> Design by DanceSmile</p>
                <p>陇ICP备14000352号-1</p>
                </p>
            </ul>
        </div>
    </aside>
    <script src="http://localhost:8080/static/www/blog/js/silder.js"></script>
    <div class="clear"></div>
    <!-- 清除浮动 -->
</div>
</body>
</html>
